#ifndef  GAME_HPP
# define GAME_HPP

# include "datatree.hpp"
# include "renderressources.hpp"
# include "ui.hpp"
# include "loadedlib.hpp"
# include "errormanager.hpp"
# include "soundmanager.hpp"
# include <stack>
# include <list>

namespace Shiny
{
   class Level
   {
   public:
     Level(void) : _hud(0), _displayFps(false), _fps(0) {}
     virtual ~Level();

    virtual void                Update(void)     = 0;
    virtual Widgets::Container* CreateView(void) = 0;
    void                        Render(sf::RenderTarget&);
    void                        AddView(Widgets::Container* view);
    void                        DelView(Widgets::Container* view);
    Widgets::Ui*                Hud(void)                         { return (_hud);          }
    void                        SetEventManager(EventManager* em) { _eventManager = em;     }
    EventManager*               GetEventManager(void)             { return (_eventManager); }
    void                        DisplayFps(bool set) { _displayFps = set; }

   protected:
    Widgets::Ui*      _hud;
    EventManager*     _eventManager;
    std::list<Widgets::Container*> _cameras;

  private:
    void              DoDisplayFps(sf::RenderTarget&);

    bool              _displayFps;
    unsigned int      _fps;
    sf::Clock         _fpsClock;
    sf::Text          _fpsText;
  };

  class MainScript
  {
  public:
    virtual ~MainScript() {}
    virtual void DrawMenuBackground(sf::RenderTarget&);

  protected:
  };

  class Game
  {
    friend class ErrorManager;
    typedef std::list<std::pair<std::string, std::string> > LevelList;
    typedef std::stack<Level*>                              LevelPile;
    typedef MainScript* (*ScriptFactory)(Game&, Widgets::Ui&);

  public:
    typedef Level*      (*LevelFactory)(const std::string& levelPath, Data);

    Game(Data);
    ~Game();

    void          SetMainScript(MainScript*);
    void          LoadLevel(LevelFactory factory, const std::string& key);
    Level*        CurrentLevel(void);
    void          EndLevel(void);
    void          EndGame(void)        { _running = false; }
    void          SetPause(bool pause) { _pause   = pause; }
    int           Execute(void);

    void          SetResolution(const sf::Vector2f&);
    void          SetWindowTitle(const std::string&);
    void          SetFullscreen(bool);
    sf::Vector2f  ScreenSize(void) const;
    
    Widgets::Ui*  GetMainMenu(void) { return (_mainMenu); }

  private:
    void          DoEndLevel(void);
    void          ExecuteLevel(void);
    void          ExecuteMainMenu(void);
    
    EventManager      _eventManager;
    ErrorManager      _errorManager;
    SoundManager      _soundManager;
    TextureList*      _uiTextures;
    sf::RenderWindow* _window;
    Utils::LoadedLib* _libMain;
    MainScript*       _main;
    LevelList         _levelList;
    LevelPile         _currentLevels;
    Widgets::Ui*      _mainMenu;
    bool              _running;
    bool              _pause;
    bool              _fullscreen;
    std::string       _windowTitle;

    bool              _syncEndLevel;
  };
}

#endif
